package com.dkd.manage.service.impl;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson2.JSON;
import com.dkd.common.core.domain.AjaxResult;
import com.dkd.common.core.domain.entity.SysRole;
import com.dkd.common.core.domain.entity.SysUser;
import com.dkd.common.utils.DateUtils;
import com.dkd.common.utils.SecurityUtils;
import com.dkd.manage.domain.Role;
import com.dkd.manage.domain.vo.SignRankVo;
import com.dkd.manage.mapper.RegionMapper;
import com.dkd.manage.mapper.RoleMapper;
import com.dkd.system.domain.SysUserRole;
import com.dkd.system.mapper.SysRoleMapper;
import com.dkd.system.mapper.SysUserMapper;
import com.dkd.system.mapper.SysUserRoleMapper;
import com.sun.imageio.plugins.common.BitFile;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.dkd.manage.mapper.EmpMapper;
import com.dkd.manage.domain.Emp;
import com.dkd.manage.service.IEmpService;

/**
 * 员工列表Service业务层处理
 *
 * @author 赵昊鹏
 * @date 2024-10-10
 */
@Service

public class EmpServiceImpl implements IEmpService
{
    @Autowired
    private EmpMapper empMapper;

    @Autowired
    private RegionMapper regionMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    // 缓存key前缀
    private static final String SIGN_KEY_PREFIX = "sign:";
    private static final String SIGN_STATS_KEY_PREFIX = "sign:stats:";
    private static final String SIGN_RANK_KEY = "sign:rank";

    // 缓存过期时间
    private static final long STATS_CACHE_HOURS = 24; // 统计数据缓存24小时
    private static final long RANK_CACHE_MINUTES = 30; // 排行榜缓存30分钟

    /**
     * 查询员工列表
     *
     * @param id 员工列表主键
     * @return 员工列表
     */
    @Override
    public Emp selectEmpById(Long id)
    {
        return empMapper.selectEmpById(id);
    }

    /**
     * 查询员工列表列表
     *
     * @param emp 员工列表
     * @return 员工列表
     */
    @Override
    public List<Emp> selectEmpList(Emp emp)
    {
        return empMapper.selectEmpList(emp);
    }

    /**
     * 新增员工列表
     *
     * @param emp 员工列表
     * @return 结果
     */
    @Override
    public int insertEmp(Emp emp)
    {
        //补充区域名称
        emp.setRegionName(regionMapper.selectRegionById(emp.getRegionId()).getRegionName());
        //补充角色信息
        Role role=roleMapper.selectRoleByRoleId(emp.getRoleId());
        emp.setRoleName(role.getRoleName());
        emp.setRoleCode(role.getRoleCode());
        emp.setCreateTime(DateUtils.getNowDate());
        int result = empMapper.insertEmp(emp);



        return result;
    }

    /**
     * 修改员工列表
     *
     * @param emp 员工列表
     * @return 结果
     */
    @Override
    public int updateEmp(Emp emp)
    {
        //补充区域名称
        emp.setRegionName(regionMapper.selectRegionById(emp.getRegionId()).getRegionName());
        //补充角色信息
        Role role=roleMapper.selectRoleByRoleId(emp.getRoleId());
        emp.setRoleName(role.getRoleName());
        emp.setRoleCode(role.getRoleCode());
        emp.setUpdateTime(DateUtils.getNowDate());
        return empMapper.updateEmp(emp);
    }

    /**
     * 批量删除员工列表
     *
     * @param ids 需要删除的员工列表主键
     * @return 结果
     */
    @Override
    public int deleteEmpByIds(Long[] ids)
    {
        return empMapper.deleteEmpByIds(ids);
    }

    /**
     * 删除员工列表信息
     *
     * @param id 员工列表主键
     * @return 结果
     */
    @Override
    public int deleteEmpById(Long id)
    {
        return empMapper.deleteEmpById(id);
    }

    /**
     * 根据用户ID查找员工ID
     *
     * @param userId 用户ID
     * @return 员工ID
     */
    @Override
    public Long selectIdByUserId(Long userId) {
        return empMapper.selectIdByUserId(userId);
    }

    /**
     * 根据用户ID进行员工签到
     * @param userId
     * @return
     */
    @Override
    public AjaxResult sign(Long userId) {
        try {
            LocalDateTime now = LocalDateTime.now();
            String keySuffix = now.format(DateTimeFormatter.ofPattern("yyyMM"));
            String key = SIGN_KEY_PREFIX + keySuffix + ":" + userId;
            int dayOfMonth = now.getDayOfMonth();

            // 设置签到
            stringRedisTemplate.opsForValue().setBit(key, dayOfMonth-1, true);

            // 清除该用户的统计缓存和排行榜缓存
            String statsCacheKey = SIGN_STATS_KEY_PREFIX + keySuffix + ":" + userId;
            String rankCacheKey = SIGN_RANK_KEY + ":" + keySuffix;
            stringRedisTemplate.delete(statsCacheKey);
            stringRedisTemplate.delete(rankCacheKey);

            return AjaxResult.success("签到成功");
        } catch (Exception e) {
            return AjaxResult.error("签到失败：" + e.getMessage());
        }
    }

    @Override
    public AjaxResult signCount(Long userId) {
        try {
            LocalDateTime now = LocalDateTime.now();
            String keySuffix = now.format(DateTimeFormatter.ofPattern("yyyMM"));
            String statsCacheKey = SIGN_STATS_KEY_PREFIX + keySuffix + ":" + userId;

            // 尝试从缓存获取
            String statsJson = stringRedisTemplate.opsForValue().get(statsCacheKey);
            if (statsJson != null) {
                return AjaxResult.success(JSON.parseObject(statsJson, Map.class));
            }

            // 缓存未命中，计算签到统计
            String signKey = SIGN_KEY_PREFIX + keySuffix + ":" + userId;
            int dayOfMonth = now.getDayOfMonth();

            List<Long> result = stringRedisTemplate.opsForValue().bitField(signKey,
                    BitFieldSubCommands.create()
                            .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth))
                            .valueAt(0)
            );

            // 处理空结果
            if (result == null || result.isEmpty() || result.get(0) == null) {
                Map<String, Object> emptyData = new HashMap<String, Object>() {{
                    put("count", 0);
                    put("consecutiveCount", 0);
                }};
                // 缓存空结果
                stringRedisTemplate.opsForValue().set(statsCacheKey,
                        JSON.toJSONString(emptyData),
                        STATS_CACHE_HOURS,
                        TimeUnit.HOURS);
                return AjaxResult.success(emptyData);
            }

            // 计算签到统计
            Long num = result.get(0);
            int count = 0;
            int currentConsecutive = 0;
            int maxConsecutive = 0;

            // 从最近的一天开始往前统计
            for (int i = dayOfMonth - 1; i >= 0; i--) {
                if ((num & (1L << i)) != 0) {
                    count++;
                    currentConsecutive++;
                    maxConsecutive = Math.max(maxConsecutive, currentConsecutive);
                } else {
                    maxConsecutive = Math.max(maxConsecutive, currentConsecutive);
                    currentConsecutive = 0;
                }
            }

            maxConsecutive = Math.max(maxConsecutive, currentConsecutive);

            Map<String, Object> data = new HashMap<>();
            data.put("count", count);
            data.put("consecutiveCount", maxConsecutive);

            // 缓存结果24小时
            stringRedisTemplate.opsForValue().set(statsCacheKey,
                    JSON.toJSONString(data),
                    STATS_CACHE_HOURS,
                    TimeUnit.HOURS);

            return AjaxResult.success(data);
        } catch (Exception e) {
            return AjaxResult.error("获取签到统计失败：" + e.getMessage());
        }
    }

    @Override
    public int signStatus(Long userId) {
        try {
            LocalDateTime now = LocalDateTime.now();
            String keySuffix = now.format(DateTimeFormatter.ofPattern("yyyMM"));
            String key = SIGN_KEY_PREFIX + keySuffix + ":" + userId;
            int dayOfMonth = now.getDayOfMonth();

            Boolean isSigned = stringRedisTemplate.opsForValue().getBit(key, dayOfMonth - 1);
            return isSigned != null && isSigned ? 1 : 0;
        } catch (Exception e) {
            return 0;
        }
    }

    @Override
    public AjaxResult signRank() {
        try {
            LocalDateTime now = LocalDateTime.now();
            String keySuffix = now.format(DateTimeFormatter.ofPattern("yyyMM"));
            String rankCacheKey = SIGN_RANK_KEY + ":" + keySuffix;

            // 尝试从缓存获取排行榜
            String rankJson = stringRedisTemplate.opsForValue().get(rankCacheKey);
            if (rankJson != null) {
                return AjaxResult.success(JSON.parseArray(rankJson, SignRankVo.class));
            }

            // 缓存未命中，计算排行榜
            List<SignRankVo> rankList = calculateSignRank();

            // 缓存排行榜结果5分钟
            stringRedisTemplate.opsForValue().set(rankCacheKey,
                    JSON.toJSONString(rankList),
                    RANK_CACHE_MINUTES,
                    TimeUnit.MINUTES);

            return AjaxResult.success(rankList);
        } catch (Exception e) {
            return AjaxResult.error("获取签到排行榜失败：" + e.getMessage());
        }
    }

    // 计算签到排行榜的具体实现
    private List<SignRankVo> calculateSignRank() {
        LocalDateTime now = LocalDateTime.now();
        String keySuffix = now.format(DateTimeFormatter.ofPattern("yyyMM"));
        int dayOfMonth = now.getDayOfMonth();

        List<Emp> emps = empMapper.selectAllActiveEmps();
        List<SignRankVo> rankList = new ArrayList<>();

        for (Emp emp : emps) {
            String key = SIGN_KEY_PREFIX + keySuffix + ":" + emp.getUserId();
            List<Long> result = stringRedisTemplate.opsForValue().bitField(
                    key,
                    BitFieldSubCommands.create()
                            .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth))
                            .valueAt(0)
            );

            if (result != null && !result.isEmpty() && result.get(0) != null) {
                Long num = result.get(0);
                SignRankVo rankVo = new SignRankVo();
                rankVo.setUserId(emp.getUserId());
                rankVo.setUserName(emp.getUserName());

                int count = 0;
                int currentConsecutive = 0;
                int maxConsecutive = 0;

                for (int i = dayOfMonth - 1; i >= 0; i--) {
                    if ((num & (1L << i)) != 0) {
                        count++;
                        currentConsecutive++;
                        maxConsecutive = Math.max(maxConsecutive, currentConsecutive);
                    } else {
                        maxConsecutive = Math.max(maxConsecutive, currentConsecutive);
                        currentConsecutive = 0;
                    }
                }

                maxConsecutive = Math.max(maxConsecutive, currentConsecutive);
                rankVo.setSignCount(count);
                rankVo.setConsecutiveCount(maxConsecutive);
                rankList.add(rankVo);
            }
        }

        rankList.sort((a, b) -> {
            int compareResult = b.getSignCount().compareTo(a.getSignCount());
            if (compareResult == 0) {
                return b.getConsecutiveCount().compareTo(a.getConsecutiveCount());
            }
            return compareResult;
        });

        return rankList;
    }
}
